#!/bin/bash
#Time:2015-3-20
#Author:www.isjian.com
#Version:2.1
#Update:2016-03-15

###说明:
#1.在centos6.x平台上测试通过.
#2.列出当前宿主机上所有运行中的虚拟机(KVM)详细信息.

###更新日志
## 2016-01-25
#1.更新版本为2.1
#2.增加"-s"参数，可以计算出所有虚机占用的总虚拟cpu，虚拟内存，虚机磁盘，以及当前所使用的物理磁盘空间
## 2016-01-21
#1.更新版本为2.0
#2.使用"-i"参数可获取虚拟机ip地址,此命令运行后会提示用户是否进行arp广播,若选择不进行arp广播，可能无法获取某些虚机ip地址
#注意:此方法首先利用arp广播更新系统arp表,再由虚机mac地址匹配出其ip地址，若不希望进行arp广播，可在随后提示中使用"n"
#3.无法获取ip地址的虚拟机会显示"noip".
#4.使用"-d"参数可显示虚机所有虚拟磁盘文件及其大小,大小格式为"[a][b]",a值表示此虚拟磁盘文件所占物理硬盘大小，b值表示虚拟磁盘虚拟大小
#5.使用"-h"可显示帮助菜单
## 2015-11-24
#1.更新版本为1.6.
#2.使用"-i"参数可显示虚拟机ip地址.
#3.无法获取ip地址的虚拟机会用"-"代替.
##2015-9-15
#1.更新版本为1.5
#2.可显示虚机每块磁盘大小.
#3.默认只列出虚机的根磁盘，加上"-d"参数可列出所有磁盘.

#get vms name and print to /tmp/vmhost.txt
#"break" can shorten the awk running time,even though very short
function Get_Vmnames() {
	ps aux | grep "qemu-kvm " | grep -v 'grep' | \
		awk '{
				for(i=1;i<=NF;i++) {
					if($i == "-name"){ print $(i+1);break }
				}
		}' >> /tmp/vmhost.txt
}

#Use of a domain name as the parameter and output it's %cpu,%mem,port on one line
function Get_Consoleinfo () {
	ps aux | grep "qemu-kvm" | grep -v grep | grep " \-name $1 " | egrep "( \-spice port| \-vnc )" | \
		awk '{
			for(i=1;i<=NF;i++){
				if($i == "-spice") {
					Port=$(i+1)
					print $2,$3,$4,"spice:"substr(Port,1,match(Port,/,addr.*/)-1) }
				else if($i == "-vnc") {
					Port=$(i+1);
					print $2,$3,$4,"vnc:"substr(Port,match(Port,/:.*/)+1)+5900 }
				}
		}' | sed -r "s/(port=|tls-port=)//g"
}

#get arp table
function Get_Arptable() {
	read -p "Whether to use arp broadcast(y|n):" whether
	if [ "${whether}" == "y" ];then
		IpLists=`ifconfig | awk '/inet addr/ && !/127.0.0.1/ {print substr($2,6)}' | cut -d. -f 1-3`
		for iip in $IpLists
		do
			for ij in `seq 1 254`;do
				( ping -W 1 -c 1 ${iip}.${ij} &>/dev/null) &
			done
			wait
		done
	fi
}

#get vhost cpu,memory
function Get_Vcpuvmems() {
	virsh dominfo "$1" | \
		awk '
				/^CPU\(s\)/ {print $2}
				/^Used memory/ {print $3/1024/1024"G"}
					' | xargs
}

#get vhost block
function Get_Vmblk() {
	blklist=$(virsh domblklist "$1" | awk 'NR>=3{if($2 != "-" && NF>=1) print $1":"$2}' | xargs)
	declare -i num && num=1
	for ii in ${blklist}
	do 
		blkbasename=`basename ${ii}`
		qemu-img info $(echo $ii | awk -F '[:]' '{print $2}') | \
			awk -v a="$ii" -v b="${blkbasename}" -v c="${num}" -v d="f${alter}" '
						/^virtual size:/ {Vsize=$3}
						/^disk size:/ {if($3 ~ /M/ && d == "f-s") Dsize=int(substr($3,1,match($3,/M/)-1)/1024*100)/100"G";else Dsize=$3}
						END{
							if(d == "f-s") print "d:"Dsize":v:"Vsize
							else if(d == "f-d") print a"["Dsize"]""["Vsize"]"
							else if(c >= 2) print "["Dsize"]""["Vsize"]"
							else print a"["Dsize"]""["Vsize"]"
																											}'
		num+=1
	done | xargs | sed "s/ /,/g"
}

#get vmip
function Get_Vmip() {
	vm_mac="`virsh domiflist "$1" | awk 'NR>2{if($0 != "") print $5}' | xargs`"	vm_mac=${vm_mac:-no_mac}
			iplists=`
					for ik in ${vm_mac}
					do
						arp -n | grep -i "${ik}" | awk '{print $1}'
					done | xargs | sed "s/ /,/g" `
	echo ${iplists:-noip}
}

function usage() {
	    echo "option args: [-d | -i | -s ]"
			        echo "usage:"
					        echo "-d      display all the disks and it's size"
	echo "-i      display the vm ip"
	echo "-s      display the total resources"
	echo "-h      display this help"
}

function format_line() {
	Get_Vmnames
	[ "${alter}" == "-i" ] && Get_Arptable

	for i in `cat /tmp/vmhost.txt | awk '{print $1}'`;do
		if [ "${alter}" == "-d" ];then
			blkinfo_temp="`Get_Vmblk ${i}`"
			blkinfo=$(echo ${blkinfo_temp} | sed -r 's/\//\\\//g')
			sed -i -r "/^${i}/s/.*/& ${blkinfo}/g" /tmp/vmhost.txt
		elif [ "${alter}" == "-i" ];then
			vmipinfo="`Get_Vmip ${i}`"
			sed -i -r "/^${i}/s/.*/& ${vmipinfo}/g" /tmp/vmhost.txt
		elif [ "${alter}" == "-s" ];then
			vcpumem="`Get_Vcpuvmems ${i}`"
			blkinfo_temp="`Get_Vmblk ${i}`"
			blkinfo=$(echo ${blkinfo_temp} | sed -r 's/\//\\\//g')
			sed -i -r "/^${i}/s/.*/& ${vcpumem} ${blkinfo}/g" /tmp/vmhost.txt
		else
			consoleinfo="`Get_Consoleinfo ${i}`"
			vcpumem="`Get_Vcpuvmems ${i}`"
			blkinfo_temp="`Get_Vmblk ${i}`"
			blkinfo=$(echo ${blkinfo_temp} | sed -r 's/\//\\\//g')
			sed -i -r "/^${i}/s/.*/& ${consoleinfo} ${vcpumem} ${blkinfo}/g" /tmp/vmhost.txt
			
		fi
	done
}


function format_printf() {
	/bin/rm -f /tmp/vmhost.txt
	format_line

	Length_tmp=$(cat /tmp/vmhost.txt | awk 'BEGIN{A=0} {if(length($1)>=A) A=length($1)} END{print A}')
	Length=$((Length_tmp + 5))

	case ${alter} in
		-d)
			cat /tmp/vmhost.txt | \
				awk -v L=${Length} '
					BEGIN{printf "%-*s %-15s\n",L,"VHOSTS","Vdisks";for(i=1;i<=46;i++)printf "---";print ""}
		{printf "%-*s %-15s\n",L,$1,$2}'
		    ;;

		-i)
			cat /tmp/vmhost.txt | \
				awk -v L=${Length} '
						BEGIN{printf "%-*s %-15s\n",L,"VHOSTS","Vip";for(i=1;i<=14;i++)printf "---";print ""}
			{printf "%-*s %-15s\n",L,$1,$2}'
			;;

		-s)
			cat /tmp/vmhost.txt | sed "s/G//g" | \
				awk -F'[ :,]' '
								BEGIN{ a=0;b=0 } {
											for(i=1;i<=NF;i++){
															if($i == "d") a+=$(i+1);
																		else if($i == "v") b+=$(i+1) 
																					};
													c+=$2;
															m+=$3 }
					END { printf "%-20s %-20s %-20s %-20s\n","Vcpus","Vmems","DiskUsage","VdiskUsage";for(i=1;i<=34;i++)printf "---";print ""}
							END { printf "%-20s %-20s %-20s %-20s\n",c,m,b"G",a"G" }
								'
			;;

		-h)
			usage
			;;

		*)
			cat /tmp/vmhost.txt | \
				awk -v L=${Length} 'BEGIN{printf "%-*s %-7s %-6s %-6s %-12s %-6s %-6s %-20s\n",L,"VHOSTS","PID","%CPU","%MEM","PORT","Vcpus","Vmems","Vdisks";for(i=1;i<=46;i++)printf "---";print ""}
									{printf "%-*s %-7s %-6s %-6s %-12s %-6s %-6s %-20s\n",L,$1,$2,$3,$4,$5,$6,$7,$8}'
			;;
	esac
	/bin/rm -f /tmp/vmhost.txt
}

alter=$1
format_printf
